package router

import (
	"bytes"
	"github.com/geekerstar/libv/format/ts"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"live-core/core"
	"live-core/logging"
	"time"
)

func StreamHLSM3U8(c *gin.Context) {
	if !core.StreamManager.ChannelExist(c.Param("uuid"), c.Param("channel")) {
		c.IndentedJSON(500, Message{Status: 0, Payload: core.ErrorStreamNotFound.Error()})
		logging.ZapLog.Error(core.ErrorStreamNotFound.Error(),
			zap.String("stream", c.Param("uuid")), zap.String("channel", c.Param("channel")),
			zap.String("call", "ChannelExist"))
		return
	}
	c.Header("Content-Type", "application/x-mpegURL")
	core.StreamManager.ChannelRun(c.Param("uuid"), c.Param("channel"))
	for i := 0; i < 40; i++ {
		index, seq, err := core.StreamManager.StreamHLSm3u8(c.Param("uuid"), c.Param("channel"))
		if err != nil {
			c.IndentedJSON(500, Message{Status: 0, Payload: err.Error()})
			logging.ZapLog.Error(err.Error(), zap.String("stream", c.Param("uuid")), zap.String("channel",
				c.Param("channel")), zap.String("call", "StreamHLSm3u8"))
			return
		}
		if seq >= 6 {
			_, err := c.Writer.Write([]byte(index))
			if err != nil {
				c.IndentedJSON(400, Message{Status: 0, Payload: err.Error()})
				logging.ZapLog.Error(err.Error(),
					zap.String("stream", c.Param("uuid")), zap.String("channel", c.Param("channel")),
					zap.String("call", "Write"))
				return
			}
			return
		}
		time.Sleep(1 * time.Second)
	}
}

func StreamHLSTS(c *gin.Context) {
	if !core.StreamManager.ChannelExist(c.Param("uuid"), c.Param("channel")) {
		c.IndentedJSON(500, Message{Status: 0, Payload: core.ErrorStreamNotFound.Error()})
		logging.ZapLog.Error(core.ErrorStreamNotFound.Error(),
			zap.String("stream", c.Param("uuid")), zap.String("channel", c.Param("channel")),
			zap.String("call", "ChannelExist"))

		return
	}
	codecs, err := core.StreamManager.ChannelCodecs(c.Param("uuid"), c.Param("channel"))
	if err != nil {
		c.IndentedJSON(500, Message{Status: 0, Payload: err.Error()})
		logging.ZapLog.Error(err.Error(),
			zap.String("stream", c.Param("uuid")), zap.String("channel", c.Param("channel")),
			zap.String("call", "StreamCodecs"))

		return
	}
	outfile := bytes.NewBuffer([]byte{})
	Muxer := ts.NewMuxer(outfile)
	Muxer.PaddingToMakeCounterCont = true
	err = Muxer.WriteHeader(codecs)
	if err != nil {
		c.IndentedJSON(500, Message{Status: 0, Payload: err.Error()})
		logging.ZapLog.Error(err.Error(),
			zap.String("stream", c.Param("uuid")), zap.String("channel", c.Param("channel")),
			zap.String("call", "WriteHeader"))

		return
	}
	seqData, err := core.StreamManager.StreamHLSTS(c.Param("uuid"), c.Param("channel"), core.StringToInt(c.Param("seq")))
	if err != nil {
		c.IndentedJSON(500, Message{Status: 0, Payload: err.Error()})
		logging.ZapLog.Error(err.Error(),
			zap.String("stream", c.Param("uuid")), zap.String("channel", c.Param("channel")), zap.String("call", "StreamHLSTS"))
		return
	}
	if len(seqData) == 0 {
		c.IndentedJSON(500, Message{Status: 0, Payload: core.ErrorStreamNotHLSSegments.Error()})
		logging.ZapLog.Error(core.ErrorStreamNotHLSSegments.Error(),
			zap.String("stream", c.Param("uuid")), zap.String("channel", c.Param("channel")), zap.String("call", "seqData"))
		return
	}
	for _, v := range seqData {
		v.CompositionTime = 1
		err = Muxer.WritePacket(*v)
		if err != nil {
			c.IndentedJSON(500, Message{Status: 0, Payload: err.Error()})
			logging.ZapLog.Error(err.Error(),
				zap.String("stream", c.Param("uuid")), zap.String("channel", c.Param("channel")), zap.String("call", "WritePacket"))
			return
		}
	}
	err = Muxer.WriteTrailer()
	if err != nil {
		c.IndentedJSON(500, Message{Status: 0, Payload: err.Error()})
		logging.ZapLog.Error(err.Error(),
			zap.String("stream", c.Param("uuid")), zap.String("channel", c.Param("channel")), zap.String("call", "WriteTrailer"))

		return
	}
	_, err = c.Writer.Write(outfile.Bytes())
	if err != nil {
		c.IndentedJSON(400, Message{Status: 0, Payload: err.Error()})
		logging.ZapLog.Error(err.Error(),
			zap.String("stream", c.Param("uuid")), zap.String("channel", c.Param("channel")), zap.String("call", "Write"))
		return
	}
}
